/*
 * Log.h
 *
 *  Created on: Jul 2, 2024
 *      Author: root
 */

#ifndef BSP_LOG_LOG_H_
#define BSP_LOG_LOG_H_

#include <iostream>
#include "basic_header.h"
#include "../ringbuffer/RingBuffer.h"

#include "LogFile.h"

namespace bsp {

#ifndef TAG
#define TAG "log"
#endif

#define LOG_BASE(level,...) do{ \
			bsp::Log::getInstance()->log(level,TAG,__VA_ARGS__);\
	}while(0)

#define LOG_D(...) LOG_BASE(bsp::Log::Level::DEBUG,__VA_ARGS__)
#define LOG_I(...) LOG_BASE(bsp::Log::Level::INFO,__VA_ARGS__)
#define LOG_W(...)	LOG_BASE(bsp::Log::Level::WARN,__VA_ARGS__)
#define LOG_E(...)	LOG_BASE(bsp::Log::Level::ERROR,__VA_ARGS__)

class Log {
public:
	enum class Level : uint8_t {
		DEBUG, INFO, WARN, ERROR
	};

private:
	char buffer[COMMON_BUFFER_SIZE];
	bool quit;
	std::mutex mtx;
	std::unique_ptr<RingBuffer> ring_buffer;
	std::unique_ptr<std::thread> thread;
	std::condition_variable consumer;
	std::unique_ptr<LogFile> logfile;

	bool time_on;
	bool console_output_on;
	Level level;

	void asyncOutput();
	Log(std::unique_ptr<RingBuffer> &ringbuf, std::unique_ptr<LogFile> &logfile,
			Level level = Level::DEBUG, bool time_on = true,
			bool console_output_on = true);
	virtual ~Log();

public:

	static Log* getInstance() {
		static std::unique_ptr<RingBuffer> ringbuf =
				std::make_unique<RingBuffer>(LOG_RING_BUFFER_SIZE);
		static std::unique_ptr<LogFile> file = std::make_unique<LogFile>(
				LOG_FILE_NAME, LOG_FILE_MAX_SIZE, LOG_FILE_REWRITE_TAIL_SIZE, LOG_FILE_ON);
		static Log log(ringbuf, file, LOG_LEVEL,LOG_TIME_ON,LOG_CONSOLE_ON);
		return &log;
	}


	void log(Log::Level, const char *tag, const char *fmt, ...);

	void setTimeOn(bool on) {
		time_on = on;
	}

	void setConsoleOutput(bool on) {
		console_output_on = on;
	}

	void setLevel(Level lv) {
		level = lv;
	}

	Level getLevel() {
		return level;
	}

	static void test1();
};

} /* namespace bsp */

#endif /* BSP_LOG_LOG_H_ */
